<?php
/**
 +------------------------------------------------------------------------------
 *  IP 地理位置查询类 修改自Discuz
 *  由于使用UTF8编码 如果使用纯真IP地址库的话 需要对返回结果进行编码转换
 +------------------------------------------------------------------------------
 * @File: IIAIpIpLocation.class.php
 * @Function: 
 * @Date: 2011-4-14
 * @Author: Jackean <mosquitoyuan@163.com>
 * @Copyright: www.iialab.com
 * @Version: 
 +------------------------------------------------------------------------------
 */

class IIAIpAddress
{
		 
	public function getIpLoca($ip='') 
	{
		if ($ip == '') $ip=$this->get_client_ip();
		
		$return = '';
		if(preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $ip)) {
			$iparray = explode('.', $ip);
			if($iparray[0] == 10 || $iparray[0] == 127 || ($iparray[0] == 192 && $iparray[1] == 168) || ($iparray[0] == 172 && ($iparray[1] >= 16 && $iparray[1] <= 31))) {
				$return = '- LAN';
			} elseif($iparray[0] > 255 || $iparray[1] > 255 || $iparray[2] > 255 || $iparray[3] > 255) {
				$return = '- Invalid IP Address';
			} else {
				//tinyipdata.dat 可以从discuz官方获取，放置于你网站Public目录
				$tinyipfile = __PUBLIC__.'/ipdata/tinyipdata.dat';
				$fullipfile = __PUBLIC__.'/ipdata/wry.dat';
				if(@file_exists($tinyipfile))
			    {
					$return = $this->queryin_tiny($ip, $tinyipfile);
				} elseif(@file_exists($fullipfile)) 
				{
					$return = $this->queryin_wry($ip, $fullipfile);
					$return = $this->auto_charset($return);
				}
			}
		}
		return $return;
	}
	
	private function queryin_tiny($ip, $ipdatafile)
	{

		static $fp = NULL, $offset = array(), $index = NULL;
		$ipdot = explode('.', $ip);
		$ip    = pack('N', ip2long($ip));
		$ipdot[0] = (int)$ipdot[0];
		$ipdot[1] = (int)$ipdot[1];

		if($fp === NULL && $fp = @fopen($ipdatafile, 'rb')) {
			$offset = @unpack('Nlen', @fread($fp, 4));
			$index  = @fread($fp, $offset['len'] - 4);
		} elseif($fp == FALSE) {
			return  '- Invalid IP data file';
		}

		$length = $offset['len'] - 1028;
		$start  = @unpack('Vlen', $index[$ipdot[0] * 4] . $index[$ipdot[0] * 4 + 1] . $index[$ipdot[0] * 4 + 2] . $index[$ipdot[0] * 4 + 3]);

		for ($start = $start['len'] * 8 + 1024; $start < $length; $start += 8) {

			if ($index{$start} . $index{$start + 1} . $index{$start + 2} . $index{$start + 3} >= $ip) {
				$index_offset = @unpack('Vlen', $index{$start + 4} . $index{$start + 5} . $index{$start + 6} . "\x0");
				$index_length = @unpack('Clen', $index{$start + 7});
				break;
			}
		}

		@fseek($fp, $offset['len'] + $index_offset['len'] - 1024);
		if($index_length['len']) {
			return '- '.@fread($fp, $index_length['len']);
		} else {
			return '- Unknown';
		}
	}
	  
    private function queryin_wry($ip, $ipdatafile)
	  {
	  
		  if(!$fd = @fopen($ipdatafile, 'rb')) {
			  return '- Invalid IP data file';
		  }
	  
		  $ip = explode('.', $ip);
		  $ipNum = $ip[0] * 16777216 + $ip[1] * 65536 + $ip[2] * 256 + $ip[3];
	  
		  if(!($DataBegin = fread($fd, 4)) || !($DataEnd = fread($fd, 4)) ) return;
		  @$ipbegin = implode('', unpack('L', $DataBegin));
		  if($ipbegin < 0) $ipbegin += pow(2, 32);
		  @$ipend = implode('', unpack('L', $DataEnd));
		  if($ipend < 0) $ipend += pow(2, 32);
		  $ipAllNum = ($ipend - $ipbegin) / 7 + 1;
	  
		  $BeginNum = $ip2num = $ip1num = 0;
		  $ipAddr1 = $ipAddr2 = '';
		  $EndNum = $ipAllNum;
	  
		  while($ip1num > $ipNum || $ip2num < $ipNum) {
			  $Middle= intval(($EndNum + $BeginNum) / 2);
	  
			  fseek($fd, $ipbegin + 7 * $Middle);
			  $ipData1 = fread($fd, 4);
			  if(strlen($ipData1) < 4) {
				  fclose($fd);
				  return '- System Error';
			  }
			  $ip1num = implode('', unpack('L', $ipData1));
			  if($ip1num < 0) $ip1num += pow(2, 32);
	  
			  if($ip1num > $ipNum) {
				  $EndNum = $Middle;
				  continue;
			  }
	  
			  $DataSeek = fread($fd, 3);
			  if(strlen($DataSeek) < 3) {
				  fclose($fd);
				  return '- System Error';
			  }
			  $DataSeek = implode('', unpack('L', $DataSeek.chr(0)));
			  fseek($fd, $DataSeek);
			  $ipData2 = fread($fd, 4);
			  if(strlen($ipData2) < 4) {
				  fclose($fd);
				  return '- System Error';
			  }
			  $ip2num = implode('', unpack('L', $ipData2));
			  if($ip2num < 0) $ip2num += pow(2, 32);
	  
			  if($ip2num < $ipNum) {
				  if($Middle == $BeginNum) {
					  fclose($fd);
					  return '- Unknown';
				  }
				  $BeginNum = $Middle;
			  }
		  }
	  
		  $ipFlag = fread($fd, 1);
		  if($ipFlag == chr(1)) {
			  $ipSeek = fread($fd, 3);
			  if(strlen($ipSeek) < 3) {
				  fclose($fd);
				  return '- System Error';
			  }
			  $ipSeek = implode('', unpack('L', $ipSeek.chr(0)));
			  fseek($fd, $ipSeek);
			  $ipFlag = fread($fd, 1);
		  }
	  
		  if($ipFlag == chr(2)) {
			  $AddrSeek = fread($fd, 3);
			  if(strlen($AddrSeek) < 3) {
				  fclose($fd);
				  return '- System Error';
			  }
			  $ipFlag = fread($fd, 1);
			  if($ipFlag == chr(2)) {
				  $AddrSeek2 = fread($fd, 3);
				  if(strlen($AddrSeek2) < 3) {
					  fclose($fd);
					  return '- System Error';
				  }
				  $AddrSeek2 = implode('', unpack('L', $AddrSeek2.chr(0)));
				  fseek($fd, $AddrSeek2);
			  } else {
				  fseek($fd, -1, SEEK_CUR);
			  }
	  
			  while(($char = fread($fd, 1)) != chr(0))
			  $ipAddr2 .= $char;
	  
			  $AddrSeek = implode('', unpack('L', $AddrSeek.chr(0)));
			  fseek($fd, $AddrSeek);
	  
			  while(($char = fread($fd, 1)) != chr(0))
			  $ipAddr1 .= $char;
		  } else {
			  fseek($fd, -1, SEEK_CUR);
			  while(($char = fread($fd, 1)) != chr(0))
			  $ipAddr1 .= $char;
	  
			  $ipFlag = fread($fd, 1);
			  if($ipFlag == chr(2)) {
				  $AddrSeek2 = fread($fd, 3);
				  if(strlen($AddrSeek2) < 3) {
					  fclose($fd);
					  return '- System Error';
				  }
				  $AddrSeek2 = implode('', unpack('L', $AddrSeek2.chr(0)));
				  fseek($fd, $AddrSeek2);
			  } else {
				  fseek($fd, -1, SEEK_CUR);
			  }
			  while(($char = fread($fd, 1)) != chr(0))
			  $ipAddr2 .= $char;
		  }
		  fclose($fd);
	  
		  if(preg_match('/http/i', $ipAddr2)) {
			  $ipAddr2 = '';
		  }
		  $ipaddr = "$ipAddr1 $ipAddr2";
		  $ipaddr = preg_replace('/CZ88\.NET/is', '', $ipaddr);
		  $ipaddr = preg_replace('/^\s*/is', '', $ipaddr);
		  $ipaddr = preg_replace('/\s*$/is', '', $ipaddr);
		  if(preg_match('/http/i', $ipaddr) || $ipaddr == '') {
			  $ipaddr = '- Unknown';
		  }
	  
		  return '- '.$ipaddr;
	  
	 }
	 
	 private function get_client_ip(){
	   if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown"))
		   $ip = getenv("HTTP_CLIENT_IP");
	   else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown"))
		   $ip = getenv("HTTP_X_FORWARDED_FOR");
	   else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown"))
		   $ip = getenv("REMOTE_ADDR");
	   else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown"))
		   $ip = $_SERVER['REMOTE_ADDR'];
	   else
		   $ip = "unknown";
	   return($ip);
	}
	 
	private function auto_charset($fContents,$from='gbk',$to='utf-8'){
		$from   =  strtoupper($from)=='UTF8'? 'utf-8':$from;
		$to       =  strtoupper($to)=='UTF8'? 'utf-8':$to;
		if( strtoupper($from) === strtoupper($to) || empty($fContents) || (is_scalar($fContents) && !is_string($fContents)) ){
			//如果编码相同或者非字符串标量则不转换
			return $fContents;
		}
		if(is_string($fContents) ) {
			if(function_exists('mb_convert_encoding')){
				return mb_convert_encoding ($fContents, $to, $from);
			}elseif(function_exists('iconv')){
				return iconv($from,$to,$fContents);
			}else{
				return $fContents;
			}
		}
	}	 
}
 ?>